package com.zyxx.common.mybatis;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;

@Slf4j
@Intercepts({@Signature(
		type = StatementHandler.class,
		method = "prepare",
		args = {Connection.class, Integer.class}
)})
public class DataScopePluginInterceptor extends AbstractSqlParserHandler implements Interceptor {

	/**
	 * 在此实现自己的拦截逻辑，可从Invocation参数中拿到执行方法的对象，方法，方法参数，从而实现各种业务逻辑, 如下代码所示，从invocation中获取的statementHandler对象即为被代理对象，基于该对象，我们获取到了执行的原始SQL语句，以及prepare方法上的分页参数，并更改SQL语句为新的分页语句，最后调用invocation.proceed()返回结果。
	 *
	 * @param invocation
	 * @return
	 * @throws Throwable
	 */
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		log.info("开始执行拦截器逻辑");

		StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
		MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
		log.info("mapperStatement: {}", mappedStatement);
		//这里拿到的method是代理之后的对象
		Method method = invocation.getMethod();

		/**
		 * 通过反射，拿到自定义注解信息
		 */
		String namespace = mappedStatement.getId();
		String className = namespace.substring(0, namespace.lastIndexOf("."));
		String methedName = namespace.substring(namespace.lastIndexOf(".") + 1, namespace.length());
		Method[] ms = Class.forName(className).getMethods();
		for (Method m : ms) {
			if (m.getName().equals(methedName)) {
				DataScope annotation = m.getAnnotation(DataScope.class);
				if (annotation != null) {
					log.info("dataScoper:{}", annotation.value());
					// 针对定义了rowBounds，做为mapper接口方法的参数
					// 通过修改BoundSql 中已解析的SQL来控制数据权限
					BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
					Object paramObj = boundSql.getParameterObject();
					String sql = boundSql.getSql();
					if (sql.contains("where")) {
						sql = sql.replace("where", "where " + annotation.value() + " and ");
					} else if (sql.contains("WHERE")) {
						sql = sql.replace("WHERE", "WHERE " + annotation.value() + " and ");
					} else if (sql.contains("order")) {
						sql = sql.replace("order", "where " + annotation.value() + " order ");
					} else if (sql.contains("ORDER")) {
						sql = sql.replace("ORDER", "where " + annotation.value() + " ORDER ");
					} else if (sql.contains("limit")) {
						sql = sql.replace("limit", "where " + annotation.value() + " limit ");
					} else if (sql.contains("LIMIT")) {
						sql = sql.replace("LIMIT", "where " + annotation.value() + " LIMIT ");
					} else {
						sql += "where " + annotation.value();
					}
					boundSql = new BoundSql(mappedStatement.getConfiguration(), sql, boundSql.getParameterMappings(), paramObj);
					metaObject.setValue("delegate.boundSql", boundSql);
//					ReflectUtil.setFieldValue(boundSql, "sql", sql);
				}
			}
			;
		}
		Object value1 = metaObject.getValue("delegate.mappedStatement.sqlCommandType");
//		String value = String.valueOf(metaObject.getValue("delegate.boundSql.sql"));
//		final Method method = invocation.getMethod();
		return invocation.proceed();
	}

	private static String getSqlByClass(Object value) {

		if (value instanceof Number) {
			return value + "";
		} else if (value instanceof String) {
			return "'" + value + "'";
		}

		return "'" + value.toString() + "'";
	}


	/**
	 * 生成代理对象；
	 *
	 * @param target
	 * @return
	 */
	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	/**
	 * 设置一些属性变量；
	 *
	 * @param properties
	 */
	@Override
	public void setProperties(Properties properties) {
		Interceptor.super.setProperties(properties);
		log.info("数据权限拦截器");
	}
}
